﻿using System;
using System.Web.Mvc;

namespace HashFoo.Rest.Server
{
    /// <summary>
    /// Binds enumerations to a model on top of the ASP MVC infrastructure.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class EnumBinder<T> : IModelBinder
    {
        private T DefaultValue { get; set; }

        /// <summary>
        /// Create the model binder with a default enum value.
        /// </summary>
        /// <param name="defaultValue"></param>
        public EnumBinder(T defaultValue)
        {
            DefaultValue = defaultValue;
        }

        /// <summary>
        /// Binds the model to a value by using the specified controller context and binding context.
        /// </summary>
        /// <returns>
        /// The bound value.
        /// </returns>
        /// <param name="controllerContext">The controller context.</param><param name="bindingContext">The binding context.</param>
        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            return bindingContext.ValueProvider.GetValue(bindingContext.ModelName) == null 
                ? DefaultValue 
                : GetEnumValue(DefaultValue, bindingContext.ValueProvider.GetValue(bindingContext.ModelName).RawValue);
        }

        /// <summary>
        /// Converts an integer object to its enum value.
        /// </summary>
        /// <param name="defaultValue"></param>
        /// <param name="rawValue"></param>
        /// <returns></returns>
        static T GetEnumValue(T defaultValue, object rawValue)
        {
            var value = rawValue;
            if (null != value)
            {
                var valueType = value.GetType();
                if (!valueType.IsEnum)
                {
                    try
                    {
                        return (T)Enum.ToObject(typeof(T), value);
                    }
                    catch
                    {
                        return defaultValue;
                    }
                }
            }

            return defaultValue;
        }
    }

}